package com.jm88.tools.myapp;

import java.io.File;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.apache.commons.lang.StringUtils;

import com.jm88.tools.bean.TypeAttribute;
import com.jm88.tools.bean.TypeNode;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
 * 自动生成ibatis 的 sql-map、Dao、Servies、Action.
 *
 * @author guanweichen
 * @version 2010-5-30, 上午10:53:41
 */
public class SSIApp {
    public static void main(String[] args) throws Exception {
    	
    	List<Class<?>> listBeanClass = new ArrayList<Class<?>>();
    	//listBeanClass.add();
    	listBeanClass.add(TypeAttribute.class);
    	listBeanClass.add(TypeNode.class);
    	// 清空target目录 的ibatis 目录
        FileUtils.cleanDirectory(new File("target/ibatis"));
    	
    	for (Class<?> beanClass : listBeanClass) {
    		writerFiles(beanClass);
		}
    }
    
	private static void writerFiles(Class<?> clazz) throws Exception {
    	
        Class<?> beanClass = clazz;
        Map<Object, Object> root = new HashMap<Object, Object>();
        List<Map<Object, Object>> props = getPropertys(beanClass);
        /*
         * 往root 里面存放数据,在模板中使用${"tableName"}
         */
        root.put("properties", props);
        root.put("tableName", getColumnName(beanClass.getSimpleName()));
        root.put("className", beanClass.getName());
        root.put("beanName", beanClass.getSimpleName());
        root.put("uncapitalizeBeanName", StringUtils.uncapitalize(beanClass.getSimpleName()));
        Configuration cfg = new Configuration();
        // 设置一个数据源,当调用Class.getResource()来加载此数据模板.
        cfg.setClassForTemplateLoading(SSIApp.class, "/");
        // 设置对象包装用于包装对象模板模型
        cfg.setObjectWrapper(new DefaultObjectWrapper());
        cfg.setDefaultEncoding("utf-8");
        // 创建目录
        new File("target/ibatis").mkdir();
        new File("target/dao").mkdir();
        new File("target/dao/impl").mkdir();
        new File("target/manager").mkdir();
        new File("target/manager/impl").mkdir();
        new File("target/action").mkdir();
        // 各个文件生成路径
        String sqlMapUrl = "target/ibatis";
        String daoUrl = "target/dao";
        String daoImplUrl = "target/dao/impl";
        String managerUrl = "target/manager";
        String managerImplUrl = "target/manager/impl";
        String actionUrl = "target/action";
        
        //个文件名
        String sqlMapFileName = "sql-map-" + getSqlMapName(beanClass.getSimpleName()) + ".xml";
        String daoFileName = beanClass.getSimpleName() + "Dao.java";
        String daoImplFileName = beanClass.getSimpleName() + "DaoImpl.java";
        String managerFileName = beanClass.getSimpleName() + "Manager.java";
        String managerImplFileName = beanClass.getSimpleName() + "ManagerImpl.java";
        String actionFileName = beanClass.getSimpleName() + "Action.java";
        
        /*
         * 设置package 路径.
         */
        // TODO 使用时修改
        root.put("actionPackage", "com.baoz.bkshfw.admin.action");
        root.put("daoPackage", "com.baoz.bkshfw.dao");
        root.put("managerPackage", "com.baoz.bkshfw.manager");
        root.put("modelPackage", "com.baoz.bkshfw.model");
        /*
         * 获得所有模板.
         */
        // TODO 切换数据库时切换sql-map 模板.
        Template temp = cfg.getTemplate("ibatis-oracle.ftl");
        Template tempDao = cfg.getTemplate("dao.ftl");
        Template tempDaoImpl = cfg.getTemplate("daoImpl.ftl");
        Template tempManager = cfg.getTemplate("manager1.ftl");
        Template tempManagerImpl = cfg.getTemplate("managerImpl.ftl");
        Template tempAction = cfg.getTemplate("action.ftl");
        /*
         * 写出文件. 
         */
        writerFile(temp, root, sqlMapUrl, sqlMapFileName);
        writerFile(tempDao, root, daoUrl, daoFileName);
        writerFile(tempDaoImpl, root, daoImplUrl, daoImplFileName);
        writerFile(tempManager, root, managerUrl, managerFileName);
        writerFile(tempManagerImpl, root, managerImplUrl, managerImplFileName);
        writerFile(tempAction, root, actionUrl, actionFileName);
    }

    private static void writerFile(Template template, Map<Object, Object> data, String fileUrl, String fileName) throws Exception{
    	Writer out = new FileWriterWithEncoding(new File(fileUrl, fileName), "utf-8");
        // 将模板数据以Map 方式,进行传输,经过内部处理,转化成模板(ibatis.ftl)中用到的freemarker标签处,传入到写出流里面.
    	template.process(data, out);
        out.close();
        System.out.println(fileName + "'s file writed success");
    }
    
    /**
     * 自省bean 的属性,已经列名,类型明.
     *
     * @param clazz
     * @return
     */
    private static List<Map<Object, Object>> getPropertys(Class<?> clazz){
    	List<Map<Object, Object>> props = new ArrayList<Map<Object, Object>>();
    	for (Field field : clazz.getDeclaredFields()) {
            Map<Object, Object> m = new HashMap<Object, Object>();
            if (!"class".equals(field.getName()) && !"serialVersionUID".equals(field.getName())) {
                m.put("propertyName", field.getName());
                m.put("propertyTypeName", field.getType().getName());
                m.put("columnName", getColumnName(field.getName()));
                props.add(m);
            }
        }
    	return props;
    }
    
    /**
     * 得到字段对应在数据库中的名字.例如: GbArea --> GB_AREA
     *
     * @param propName
     * @return
     */
    private static String getColumnName(String propName) {
        char[] chars = propName.toCharArray();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (Character.isUpperCase(c) && i > 0) {
                sb.append('_').append(c);
            } else {
                sb.append(c);
            }
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 得到sql-map 的名称,如GbArea --> gb-area.xml
     *
     * @param simpleClassName
     * @return
     */
    private static String getSqlMapName(String simpleClassName) {
        char[] chars = simpleClassName.toCharArray();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (Character.isUpperCase(c) && i > 0) {
                sb.append('-').append(c);
            } else {
                sb.append(c);
            }
        }
        return sb.toString().toLowerCase();
    }
}
